﻿//_______________________________________________________________________________________________________________________
// Copy Right (c) 2010, 2011 SapiensIT Consulting GmbH, all rights reserved
//_______________________________________________________________________________________________________________________
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//_______________________________________________________________________________________________________________________
// PROJECT:     sapiens.at.SharePoint (SharePoint 2010/V4)
//_______________________________________________________________________________________________________________________
// VERSION:     2.0
//_______________________________________________________________________________________________________________________
// DESCRIPTION: 
//_______________________________________________________________________________________________________________________
// LICENSE:     Different licens Types apply to different file types:
//               - Source code files are governed by the MICROSOFT PUBLIC LICENSE (Ms-PL)
//               - Binary files are governed by MSDN CODE GALLERY BINARY LICENSE
//               - Documentation files are governed by CREATIVE COMMONS ATTRIBUTION 3.0 LICENSE
//
//               The licenses can be found at the projects source location.
//               If you do not agree, don't use it!
// 
//_______________________________________________________________________________________________________________________
// Start SharePoint Branding, visit http://www.cliggin.com! Visit us on http://www.sapiens.at! Tell your friends! 
//_______________________________________________________________________________________________________________________
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Globalization;
using System.Reflection;
using System.Collections;

namespace Sapiens.at.SharePoint.Mail.ICalendar
{
    /// <summary>
    /// Provides tools for converting ICalendar Messages
    /// </summary>
    public class Utilities
    {
        /// <summary>
        /// Splits up the given ICalendar-String or part of the String 
        /// </summary>
        /// <param name="ICalendarString"></param>
        /// <param name="Seperators"></param>
        /// <returns>Dictionary: Key = Seperator, Value = Text from one Seperator to the other</returns>
        public static Dictionary<string, string> Split(string ICalendarString, string[] Seperators)
        {
            Dictionary<string, string> Collection = new Dictionary<string, string>();
            foreach (string seperator in Seperators)
            {
                if (!ICalendarString.Contains(seperator))
                {
                    Collection.Add(seperator, string.Empty);
                    continue;
                }

                string HelpString = ICalendarString;
                while (HelpString.Contains(seperator))
                {
                    //if a seperator is part in another seperator, check if maybe the other seperator is the next one
                    bool fOtherSep = false;
                    foreach (string s in Seperators.Where(a => a != seperator && a.Contains(seperator)))
                    {
                        if (HelpString.IndexOf(s) > 0 &&
                            HelpString.IndexOf(s) < HelpString.IndexOf(seperator))
                            fOtherSep = true;
                    }

                    HelpString = HelpString.Substring(HelpString.IndexOf(seperator) + seperator.Length);
                    if (fOtherSep) continue;

                    //get next seperator
                    int indexOfNextSeperator = int.MaxValue;
                    foreach (string nextSep in Seperators)
                    {
                        if (nextSep != seperator && (HelpString.IndexOf(nextSep) > -1) && ((indexOfNextSeperator == int.MaxValue) || (HelpString.IndexOf(nextSep) < indexOfNextSeperator)))
                        {
                            indexOfNextSeperator = HelpString.IndexOf(nextSep);
                        }
                    }
                    string value = HelpString;
                    if (indexOfNextSeperator != int.MaxValue)
                    {
                        value = HelpString.Substring(0, indexOfNextSeperator);
                    }

                    value = value.Replace("\r\n", "").TrimStart(';', ':', '=').TrimEnd(';', ':', '=');
                    if (!Collection.ContainsKey(seperator))
                        Collection.Add(seperator, value);
                }
            }
            return Collection;
        }
        /// <summary>
        /// Converts a datetime string
        /// </summary>
        /// <param name="DT">DateTimestring Format: YYYYMMDDThhmmss</param>
        /// <returns>DateTimeString YYYY-MM-DDThh:mm:ss</returns>
        public static DateTime CreateDTFormat(string DT)
        {
            try
            {
                if (!string.IsNullOrEmpty(DT))
                {
                    DT = DT.Insert(4, "-").Insert(7, "-").Insert(13, ":").Insert(16, ":");
                    if (DT.Length > 19) DT = DT.Substring(0, 19);
                    return Convert.ToDateTime(DT);
                }
            }
            catch { }
            return DateTime.MinValue;
        }
        /// <summary>
        /// Gets the current TimeZone
        /// </summary>
        /// <returns></returns>
        public static TimeZoneInfo GetCurrentTimeZone()
        {
            foreach (TimeZoneInfo tci in TimeZoneInfo.GetSystemTimeZones())
                if (tci.StandardName == System.TimeZone.CurrentTimeZone.StandardName)
                    return tci;
            return null;
        }
        public static string[] AdditionalParameters = new string[]{
          "ALTREP",
          "CN",
          "CUTYPE",
          "DELEGATED-FROM",
          "DELEGATED-TO",
          "DIR",
          "ENCODING",
          "FMTTYPE",
          "FBTYPE",
          "LANGUAGE",
          "MEMBER",
          "PARTSTAT",
          "RANGE",
          "RELATED",
          "RELTYPE",
          "ROLE",
          "RSVP",
          "SENT-BY",
          "TZID",
          "VALUE"
        };
        /// <summary>
        /// Sets all properties implementing the <see cref="CalendarKeyWordAttribute"/> attribute for the given <paramref name="Object"/>
        /// </summary>
        /// <param name="Object"></param>
        /// <param name="ICalendarString">a string that represents the ICalendar Format</param>
        public static void SetProperties(object Object, string ICalendarString)
        {
            //gets all properties implementing the CalendarKeyWordAttribute
            IEnumerable<PropertyInfo> Properties = Object.GetType().GetProperties().Where(p => p.GetCustomAttributes(typeof(CalendarKeyWordAttribute), true).Count() > 0);
            //gets all Keywords used in Object.GetType()
            string[] Seperators = Properties.Select(p => p.GetCustomAttributes(typeof(CalendarKeyWordAttribute), true).Select(ca => (ca as CalendarKeyWordAttribute).KeyWord).Single()).ToArray();
            Dictionary<string, string> SplitUpICalendar = Utilities.Split(ICalendarString, Seperators);
            foreach (PropertyInfo p in Properties)
            {
                //gets the Value associated with the property
                string KeyWord = p.GetCustomAttributes(typeof(CalendarKeyWordAttribute), true).Select(ca => (ca as CalendarKeyWordAttribute).KeyWord).Single();
                Object Value = SplitUpICalendar[KeyWord];
                string valueString = Convert.ToString(Value);
                if (p.PropertyType.IsSubclassOf(typeof(CalendarComponent)))
                {
                    CalendarComponent ic = (CalendarComponent)Activator.CreateInstance(p.PropertyType);
                    ic.Init(valueString);
                    Value = ic;
                }
                else if (p.PropertyType.IsGenericType && p.PropertyType.GetGenericArguments().Any(gt => gt.IsSubclassOf(typeof(CalendarComponent))))
                {
                    Type t = p.PropertyType.GetGenericArguments().First(gt => gt.IsSubclassOf(typeof(CalendarComponent)));
                    Type genericType = typeof(List<>).MakeGenericType(t);
                    object collection = Activator.CreateInstance(genericType);
                    do
                    {
                        string componentstring = valueString.IndexOf(KeyWord) < 0 ? valueString : valueString.Remove(valueString.IndexOf(KeyWord));
                        valueString = valueString.IndexOf(KeyWord) < 0 ? string.Empty : valueString.Substring(valueString.IndexOf(KeyWord) + KeyWord.Count());
                        CalendarComponent component = new CalendarComponent();
                        CalendarComponent ic = (CalendarComponent)Activator.CreateInstance(t);
                        ic.Init(componentstring);
                        (collection as IList).Add(ic);
                    } while (!string.IsNullOrEmpty(valueString));
                    Value = collection;
                }
                else
                {

                    foreach (string param in AdditionalParameters)
                    {
                        string result = System.Text.RegularExpressions.Regex.Match(valueString, param + @"=(?<value>[^\:\;]*)").Groups["value"].Value;
                        if (!string.IsNullOrEmpty(result))
                        {
                            valueString = valueString.Replace(param + "=" + result, "");
                        }
                    }
                    valueString = valueString.TrimStart(';').TrimStart(':');
                    if (p.PropertyType.FullName == typeof(DateTime).FullName)
                    {
                        //Convert DateTime
                        valueString = valueString.Replace(" ", "").Replace(";", "").Replace(":", "");
                        Value = Utilities.CreateDTFormat(valueString);
                    }
                    else Value = valueString;
                }
                //sets the value
                p.SetValue(Object, Value, null);
            }
        }
    }
}
